package com.crazymakercircle.mutithread.basic.use;

import com.crazymakercircle.util.Print;

import static com.crazymakercircle.util.ThreadUtil.getCurThread;
import static com.crazymakercircle.util.ThreadUtil.sleepMilliSeconds;

/**
 * Java中的线程分为两类：守护线程与用户线程。
 * 守护线程也称为后台线程，专门指在程序进程运行过程中，在后台提供某种通用服务的线程。
 * 比如，每启动一个JVM进程，都会在后台运行一系列的GC（垃圾回收）线程，这些GC线程就是守护线程，提供幕后的垃圾回收服务。
 */
public class DaemonDemo
{
    public static final int SLEEP_GAP = 500; //每一轮的睡眠时长
    public static final int MAX_TURN = 4; //用户线程执行轮次

    //守护线程实现类
    static class DaemonThread extends Thread
    {

        public DaemonThread()
        {
            super("daemonThread");
        }

        public void run()
        {
            Print.synTco("--daemon线程开始.");

            for (int i = 1; ; i++)
            {
                Print.synTco("--轮次：" + i + "--守护状态为:" + isDaemon());
                // 线程睡眠一会
                sleepMilliSeconds(SLEEP_GAP);
            }
        }

    }


    public static void main(String args[]) throws InterruptedException
    {
        /**
         * 使用守护线程时，有以下几点需要特别注意：
         * （1）守护线程必须在启动前将其守护状态设置为true，启动之后不能再将用户线程设置为守护线程，
         * 否则JVM会抛出一个InterruptedException异常。具体来说，如果线程为守护线程，
         * 就必须在线程实例的start()方法调用之前调用线程实例的setDaemon(true)，设置其daemon实例属性值为true。
         * （2）守护线程存在被JVM强行终止的风险，所以在守护线程中尽量不去访问系统资源，如文件句柄、数据库连接等。
         * 守护线程被强行终止时，可能会引发系统资源操作不负责任的中断，从而导致资源不可逆的损坏。
         * （3）守护线程创建的线程也是守护线程。在守护线程中创建的线程，新的线程都是守护线程。在创建之后，
         * 如果通过调用setDaemon(false)将新的线程显式地设置为用户线程，新的线程可以调整成用户线程。
         */
        Thread daemonThread = new DaemonThread();
        daemonThread.setDaemon(true);
        daemonThread.start();

        Thread userThread = new Thread(() ->
        {
            Print.synTco(">>用户线程开始.");
            for (int i = 1; i <= MAX_TURN; i++)
            {
                Print.synTco(">>轮次：" + i + " -守护状态为:" + getCurThread().isDaemon());
                sleepMilliSeconds(SLEEP_GAP);
            }
            Print.synTco(">>用户线程结束.");
        }, "userThread");
        userThread.start();
        //主线程合入userThread，等待userThread执行完成
//        userThread.join();
        Print.synTco(" 守护状态为:" + getCurThread().isDaemon());

        Print.synTco(" 运行结束.");
    }
}
